#include "Render/Direct3D.h"
#include "Render/TextureManager.h"
#include "Render/FontManager.h"
#include "Render/Camera.h"

#include "Game.h"

#include "Manager/InputManager.h"

#include "World/Map/ZoneManager.h"
#include "World/Entity/Player.h"
#include "World/Entity/Goblin.h"

#include "Generic/Utility.h"

Game*	Game::m_GameInstance = NULL;

Game::Game(void)
{
	m_WorldMap = 0;
	m_GameRunning = false;
	
	m_ZoneManager = NULL;
	m_Player = NULL;
	m_InputManager = NULL;
	m_Goblin = NULL;

	m_D3D = NULL;
	m_TM = NULL;
	m_FM = NULL;
	m_CameraMain = NULL;
}

Game::~Game(void)
{

}

Game* Game::GetInstance(void)
{
	if( !m_GameInstance )
		m_GameInstance = new Game();

	return m_GameInstance;
}

void Game::Initialize(HWND _hWnd, HINSTANCE _hInstance, int _width, int _height, bool _windowed, bool _vsync)
{
	// Variables
	m_WorldMap = 0;
	m_WorldWidth = 25;
	m_WorldHeight = 25;

	m_D3D = Direct3D::GetInstance();
	m_TM = TextureManager::GetInstance();
	m_InputManager = InputManager::GetInstance();
	m_FM = FontManager::GetInstance();

	// Set up directx and the texture manager
	m_D3D->Initalize(_hWnd, _width, _height, _windowed, _vsync);
	m_TM->Initialize(m_D3D->GetD3DDevice(),m_D3D->GetSprite());

	// Create camera

	if( !m_CameraMain )
		m_CameraMain = new Camera2D();

	m_CameraMain->SetD3D(m_D3D);
	m_CameraMain->SetTextureManager(m_TM);
	m_CameraMain->CreateCamera( 0, 0, _width, _height);

	// Initialize input
	m_InputManager->Initialize(_hWnd, _hInstance, DI_KEYBOARD);

	m_InputManager->AddKeyboard("UP", DIK_UP);
	m_InputManager->AddKeyboard("DOWN", DIK_DOWN);
	m_InputManager->AddKeyboard("LEFT", DIK_LEFT);
	m_InputManager->AddKeyboard("RIGHT", DIK_RIGHT);

	m_FM->Initialize();
	m_FM->LoadFont("../Resource/Default.scf", STYLE_WOWMAIL);

	// Create the world
	BuildMap();

	// Create the player
	m_Player = new Player();
	m_Player->Capture();
	m_Player->SetCamera(m_CameraMain);
	m_CameraMain->SetTarget(m_Player);

	// Create the Goblin Enemy for testing purposes
	m_Goblin = new Goblin();
	m_Goblin->Capture();
	m_Goblin->SetCamera(m_CameraMain);
	// End Testing Subjects

	// Set the game running to true
	m_GameRunning = true;
}

void Game::Update(void)
{
	m_InputManager->UpdateDevices();
	m_Player->Update(0);
	m_Goblin->Update(0);
	m_CameraMain->Update();
	// this is where I am planning on putting the display of the score.

}

void Game::Input(void)
{
	if( GetAsyncKeyState(VK_ESCAPE) )
	{
		m_GameRunning = false;
	}
	m_Player->Input();
}

void Game::Render(void)
{
	// Clear and ready the device to rendering
	m_D3D->ScreenClear();
	m_D3D->DeviceBegin();
	m_D3D->SpriteBegin();

	// We'll render the world here
	m_ZoneManager->Render(*m_CameraMain);
	m_Player->Render();
	m_Goblin->Render();
	//m_FM->Draw("STRING\n THIS IS A NEW LINE!", 0, 2, 10, 10, 0.5f, 0.5f);

	// End the devices than draw to the screen
	m_D3D->SpriteEnd();
	m_D3D->DeviceEnd();
	m_D3D->Present();
}

void Game::Shutdown(void)
{
	// Shutdowns
	SAFE_SHUTDOWN(m_ZoneManager)
	SAFE_SHUTDOWN(m_TM)
	SAFE_SHUTDOWN(m_D3D)
	SAFE_SHUTDOWN(m_InputManager)
	SAFE_SHUTDOWN(m_FM)

	// Deletes
	SAFE_ARRDELETE(m_WorldMap)
	SAFE_DELETE(m_CameraMain);

	// Release
	SAFE_RELEASE(m_Goblin)
	SAFE_RELEASE(m_Player)
}

void Game::BuildMap(void)
{
	m_ZoneManager = ZoneManager::GetInstance();
	m_ZoneManager->Initialize();
	m_ZoneManager->SetWorldSize(m_WorldWidth,m_WorldHeight);
	m_ZoneManager->CreateWorld();
}

// Accessors section, put them here and everything else above
int Game::GetWorldMapValue(const int x, const int y)
{
	if( m_WorldMap )
	{
		int position = y * m_WorldWidth + x;
		return m_WorldMap[position];
	}

	return -1;
}

int Game::GetWorldWidth(void)
{
	return m_WorldWidth;
}

int Game::GetWorldHeight(void)
{
	return m_WorldHeight;
}

TextureManager* Game::GetTextureManager(void)
{
	return m_TM;
}

InputManager* Game::GetInputManager(void)
{
	return m_InputManager;
}

ZoneManager* Game::GetZoneManager(void)
{
	return m_ZoneManager;
}

FontManager* Game::GetFontManager(void)
{
	return m_FM;
}

Direct3D* Game::GetDirect3D(void)
{
	return m_D3D;
}

Player* Game::GetPlayer(void)
{
	return m_Player;
}

Goblin* Game::GetGoblin(void)
{
	return m_Goblin;
}

// Mutators section, put them here and everything else above
void Game::SetWorldMap(const int x, const int y, const int Type)
{
	int Position = y * m_ZoneManager->GetWorldWidth() + x;
	
	m_ZoneManager->SetZoneType(Position, Type);
}

void Game::SetWorldWidth(const int Width)
{
	m_WorldWidth = Width;
}

void Game::SetWorldHeight(const int Height)
{
	m_WorldHeight = Height;
}

bool Game::GameRunning(void)
{
	return m_GameRunning;
}